package com.swak.router;

import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Predicate;

import org.springframework.util.Assert;

public interface HandlerFilterFunction<T extends Route> {

	Object filter(T request, HandlerFunction<T> next);

	default HandlerFilterFunction<T> andThen(HandlerFilterFunction<T> after) {
		Assert.notNull(after, "HandlerFilterFunction must not be null");
		return (request, next) -> {
			HandlerFunction<T> nextHandler = handlerRequest -> after.filter(handlerRequest, next);
			return filter(request, nextHandler);
		};
	}

	default HandlerFunction<T> apply(HandlerFunction<T> handler) {
		Assert.notNull(handler, "HandlerFunction must not be null");
		return request -> this.filter(request, handler);
	}

	static <T extends Route> HandlerFilterFunction<T> ofProcessor(Function<T, T> requestProcessor) {
		Assert.notNull(requestProcessor, "Function must not be null");
		return (request, next) -> next.handle(requestProcessor.apply(request));
	}

	static <T extends Route> HandlerFilterFunction<T> ofErrorHandler(Predicate<Throwable> predicate,
			BiFunction<Throwable, T, T> errorHandler) {
		Assert.notNull(predicate, "Predicate must not be null");
		Assert.notNull(errorHandler, "ErrorHandler must not be null");
		return (request, next) -> {
			try {
				return next.handle(request);
			} catch (Throwable throwable) {
				if (predicate.test(throwable)) {
					return errorHandler.apply(throwable, request);
				} else {
					throw throwable;
				}
			}
		};
	}
}
